查看原文
其他

在 Spring Boot 中,如何干掉 if else

点击关注 👉 Java技术图谱 2022-07-02

看到crossover Jie的文章《利用策略模式优化过多if else 代码》后受到启发,可以利用策略模式简化过多的if else代码。


需求


这里虚拟一个业务需求,让大家容易理解。假设有一个订单系统,里面的一个概念是根据订单的不同类型做出不同的处理。


项目结构



订单实体

/** * 订单实体 */public class OrderDTO { private String code; private BigDecimal price;

/* * 订单类型: * 1:普通订单 * 2:团购订单 * 3:促销订单 */ private String type;//getter,setter自己实现}


service接口

/** * 订单处理 */public interface IOrderService {

/** * 根据订单的不同类型做出不同的处理 * * @param dto 订单实体 * @return 为了简单,返回字符串 */ String orderHandler(OrderDTO dto);

}//实现类1@Componentpublic class OrderServiceImpl implements IOrderService {

@Override public String orderHandler(OrderDTO dto) { if ("1".equals(dto.getType())) { //普通订单处理 } else if ("2".equals(dto.getType())) { //团购订单处理 } else if ("3".equals(dto.getType())) { //促销订单处理 } //未来订单类型增加 }

}//实现类二@Componentpublic class OrderServiceImpl implements IOrderService { //使用策略模式实现 @Autowired private HandlerContext handlerContext;

@Override public String orderHandler(OrderDTO dto) { /* * 1:使用if..else实现 * 2:使用策略模式实现 */ AOrderTypeHandler instance = handlerContext.getInstance(dto.getType()); return instance.handler(dto); }

}


利用策略模式只需要2行代码就可以搞定(也可以用工厂)

HandlerContext和HandlerProccessor
/** * 订单策略模式环境 * 这个类的注入由HandlerProccessor实现 */public class HandlerContext { private Map<String, AOrderTypeHandler> handlerMap;

/** * 构造传参不能直接使用注解扫入 */ public HandlerContext(Map<String, AOrderTypeHandler> handlerMap) { this.handlerMap = handlerMap; }

/** * 获得实例 * * @param type * @return */ public AOrderTypeHandler getInstance(String type) { if (type == null) { throw new IllegalArgumentException("type参数不能为空"); } AOrderTypeHandler clazz = handlerMap.get(type); if (clazz == null) { throw new IllegalArgumentException("该类型没有在枚举OrderTypeHandlerAnno中定义,请定义:" + type); } return clazz; }

}
/** * 策略模式,处理type与实现类的映射关系 */@Componentpublic class HandlerProccessor implements BeanFactoryPostProcessor {

/** * 扫描@OrderTypeHandlerAnno注解,初始化HandlerContext,将其注册到spring容器 * * @param beanFactory bean工厂 * @throws BeansException */ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { Map<String, AOrderTypeHandler> handlerMap = new HashMap<>(); for (OrderTypeEnum temp : OrderTypeEnum.values()) { AOrderTypeHandler beanInstacle = getBeansWithAnnotation(beanFactory, AOrderTypeHandler.class, OrderTypeHandlerAnno.class, temp.getCode()); handlerMap.put(temp.getCode(), beanInstacle); } HandlerContext context = new HandlerContext(handlerMap); //单例注入 beanFactory.registerSingleton(HandlerContext.class.getName(), context); }

/* * 通过父类+注解找到实体类 */ private <T> T getBeansWithAnnotation(ConfigurableListableBeanFactory beanFactory, Class<T> manager, Class<? extends OrderTypeHandlerAnno> annotation, String code) throws BeansException { if (ObjectUtils.isEmpty(code)) { throw new RuntimeException("code is null "); } Collection<T> tCollection = beanFactory.getBeansOfType(manager).values(); for (T t : tCollection) { OrderTypeHandlerAnno orderTypeHandlerAnno = t.getClass().getAnnotation(annotation); if (ObjectUtils.isEmpty(orderTypeHandlerAnno)) { throw new RuntimeException("该注解没有写入值 :" + code); } //注解值是否与code相等 if (code.equals(orderTypeHandlerAnno.value().getCode())) { return t; } } throw new RuntimeException("通过code没有找到该注解对应的实体类 :" + code); }

}

父抽象类+注解+枚举

/** * 订单类型处理定义 * 使用抽象类,那么子类就只有一个继承了 */public abstract class AOrderTypeHandler {

/** * 一个订单类型做一件事 * * @param dto 订单实体 * @return 为了简单,返回字符串 */ abstract public String handler(OrderDTO dto);

}

/** * 订单类型注解 * 使用方式: * 1:普通订单 @OrderTypeHandlerAnno("1") * 2:团购订单 @OrderTypeHandlerAnno("2") * 3:促销订单 @OrderTypeHandlerAnno("3") */@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface OrderTypeHandlerAnno {

OrderTypeEnum value();

}

/** * 订单类型枚举 */public enum OrderTypeEnum { Normal("1", "普通"), Group("2", "团队"), Promotion("3", "促销");

private String code; //代码 private String name; //名称,描述

OrderTypeEnum(String code, String name) { this.code = code; this.name = name; }

public String getCode() { return code; }

public void setCode(String code) { this.code = code; }

public String getName() { return name; }

public void setName(String name) { this.name = name; }

/** * 根据code属性获取name属性 * * @param code * @return */ public static String getNameByCode(String code) { for (OrderTypeEnum temp : OrderTypeEnum.values()) { if (temp.getCode().equals(code)) { return temp.getName(); } } return null; }

}


业务人员实现类

//业务代码/** * 普通订单处理 */@Component@OrderTypeHandlerAnno(OrderTypeEnum.Normal)public class NormalOrderHandler extends AOrderTypeHandler {

@Override public String handler(OrderDTO dto) { return "处理普通订单"; }

}

/** * 团队订单处理 */@Component@OrderTypeHandlerAnno(OrderTypeEnum.Group)public class GroupOrderHandler extends AOrderTypeHandler {

@Override public String handler(OrderDTO dto) { return "处理团队订单"; }

}

/** * 促销订单处理 */@Component@OrderTypeHandlerAnno(OrderTypeEnum.Promotion)public class PromotionOrderHandler extends AOrderTypeHandler {

@Override public String handler(OrderDTO dto) { return "处理促销订单"; }

}


测试结果(使用chrome浏览器测试结果)



如果类型不存在


controller

/** * 策略模式 */@RestControllerpublic class StrategyController { @Resource(name = "orderServiceImpl") private IOrderService orderService;

@GetMapping("/api/order") @ResponseBody public String orderSave(OrderDTO dto) { String str = orderService.orderHandler(dto); return "{\"status\":1,\"msg\":\"保存成功\",\"data\":\"" + str + "\"}"; }

}pom.xml文档

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.kayak</groupId> <artifactId>study-design</artifactId> <version>0.0.1-SNAPSHOT</version> <name>study-design</name> <description>Demo project for Spring Boot</description>

<properties> <java.version>1.8</java.version> </properties>

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>

<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>

</project>


总结


利用策略模式可以简化复杂的if else代码,方便维护,而利用自定义注解和自注册的方式,可以方便应对需求的变更。


主要是方便了业务人员编写代码。


这个就是个人笔记,不喜勿喷。


来源:https://blog.csdn.net/hncu1306602liuqiang



Java技术交流群

有不少同学问我,大厂面试官到底喜欢问什么?想进大厂镀金。因此,我特意邀请了华为、腾讯、阿里的朋友进群,与大家一起交流经验,增长技术。

有兴趣入群的同学,可长按扫描下方二维码,一定要备注:城市+昵称+技术方向,根据格式备注,可更快被通过且邀请进群。

▲长按扫描


近期热文推荐



点个在看你最好看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存